
#include "ktvInc.h"
#include "ktvSha1.h"

/*
	100% free public domain implementation of the SHA-1
	algorithm by Dominik Reichl <Dominik.Reichl@tiscali.de>

	* modified by Trevor Hogan for use with BNBT *

	=== Test Vectors (from FIPS PUB 180-1) ===

	"abc"
		A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D

	"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
		84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1

	A million repetitions of "a"
		34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
*/


	CKtvSha1::CKtvSha1()
	{
		Reset();
	}

	CKtvSha1::~CKtvSha1()
	{
		Reset();
	}


	void CKtvSha1::Reset()
	{
		// SHA1 initialization constants
		m_state[0] = 0x67452301;
		m_state[1] = 0xEFCDAB89;
		m_state[2] = 0x98BADCFE;
		m_state[3] = 0x10325476;
		m_state[4] = 0xC3D2E1F0;

		m_count[0] = 0;
		m_count[1] = 0;
	}

	void CKtvSha1::Transform(unsigned long state[5], const unsigned char buffer[64])
	{
		unsigned long a = 0, b = 0, c = 0, d = 0, e = 0;

		SHA1_WORKSPACE_BLOCK* block;
		static unsigned char workspace[64];
		block = (SHA1_WORKSPACE_BLOCK *)workspace;
		ktvMemCpy(block, buffer, 64);

		// Copy state[] to working vars
		a = state[0];
		b = state[1];
		c = state[2];
		d = state[3];
		e = state[4];

		// 4 rounds of 20 operations each. Loop unrolled.
		KTV_SHA_R0(a,b,c,d,e, 0); KTV_SHA_R0(e,a,b,c,d, 1); KTV_SHA_R0(d,e,a,b,c, 2); KTV_SHA_R0(c,d,e,a,b, 3);
		KTV_SHA_R0(b,c,d,e,a, 4); KTV_SHA_R0(a,b,c,d,e, 5); KTV_SHA_R0(e,a,b,c,d, 6); KTV_SHA_R0(d,e,a,b,c, 7);
		KTV_SHA_R0(c,d,e,a,b, 8); KTV_SHA_R0(b,c,d,e,a, 9); KTV_SHA_R0(a,b,c,d,e,10); KTV_SHA_R0(e,a,b,c,d,11);
		KTV_SHA_R0(d,e,a,b,c,12); KTV_SHA_R0(c,d,e,a,b,13); KTV_SHA_R0(b,c,d,e,a,14); KTV_SHA_R0(a,b,c,d,e,15);
		KTV_SHA_R1(e,a,b,c,d,16); KTV_SHA_R1(d,e,a,b,c,17); KTV_SHA_R1(c,d,e,a,b,18); KTV_SHA_R1(b,c,d,e,a,19);
		KTV_SHA_R2(a,b,c,d,e,20); KTV_SHA_R2(e,a,b,c,d,21); KTV_SHA_R2(d,e,a,b,c,22); KTV_SHA_R2(c,d,e,a,b,23);
		KTV_SHA_R2(b,c,d,e,a,24); KTV_SHA_R2(a,b,c,d,e,25); KTV_SHA_R2(e,a,b,c,d,26); KTV_SHA_R2(d,e,a,b,c,27);
		KTV_SHA_R2(c,d,e,a,b,28); KTV_SHA_R2(b,c,d,e,a,29); KTV_SHA_R2(a,b,c,d,e,30); KTV_SHA_R2(e,a,b,c,d,31);
		KTV_SHA_R2(d,e,a,b,c,32); KTV_SHA_R2(c,d,e,a,b,33); KTV_SHA_R2(b,c,d,e,a,34); KTV_SHA_R2(a,b,c,d,e,35);
		KTV_SHA_R2(e,a,b,c,d,36); KTV_SHA_R2(d,e,a,b,c,37); KTV_SHA_R2(c,d,e,a,b,38); KTV_SHA_R2(b,c,d,e,a,39);
		KTV_SHA_R3(a,b,c,d,e,40); KTV_SHA_R3(e,a,b,c,d,41); KTV_SHA_R3(d,e,a,b,c,42); KTV_SHA_R3(c,d,e,a,b,43);
		KTV_SHA_R3(b,c,d,e,a,44); KTV_SHA_R3(a,b,c,d,e,45); KTV_SHA_R3(e,a,b,c,d,46); KTV_SHA_R3(d,e,a,b,c,47);
		KTV_SHA_R3(c,d,e,a,b,48); KTV_SHA_R3(b,c,d,e,a,49); KTV_SHA_R3(a,b,c,d,e,50); KTV_SHA_R3(e,a,b,c,d,51);
		KTV_SHA_R3(d,e,a,b,c,52); KTV_SHA_R3(c,d,e,a,b,53); KTV_SHA_R3(b,c,d,e,a,54); KTV_SHA_R3(a,b,c,d,e,55);
		KTV_SHA_R3(e,a,b,c,d,56); KTV_SHA_R3(d,e,a,b,c,57); KTV_SHA_R3(c,d,e,a,b,58); KTV_SHA_R3(b,c,d,e,a,59);
		KTV_SHA_R4(a,b,c,d,e,60); KTV_SHA_R4(e,a,b,c,d,61); KTV_SHA_R4(d,e,a,b,c,62); KTV_SHA_R4(c,d,e,a,b,63);
		KTV_SHA_R4(b,c,d,e,a,64); KTV_SHA_R4(a,b,c,d,e,65); KTV_SHA_R4(e,a,b,c,d,66); KTV_SHA_R4(d,e,a,b,c,67);
		KTV_SHA_R4(c,d,e,a,b,68); KTV_SHA_R4(b,c,d,e,a,69); KTV_SHA_R4(a,b,c,d,e,70); KTV_SHA_R4(e,a,b,c,d,71);
		KTV_SHA_R4(d,e,a,b,c,72); KTV_SHA_R4(c,d,e,a,b,73); KTV_SHA_R4(b,c,d,e,a,74); KTV_SHA_R4(a,b,c,d,e,75);
		KTV_SHA_R4(e,a,b,c,d,76); KTV_SHA_R4(d,e,a,b,c,77); KTV_SHA_R4(c,d,e,a,b,78); KTV_SHA_R4(b,c,d,e,a,79);

		// Add the working vars back into state[]
		state[0] += a;
		state[1] += b;
		state[2] += c;
		state[3] += d;
		state[4] += e;

		// Wipe variables
		a = 0; b = 0; c = 0; d = 0; e = 0;
	}

	// Use this function to hash in binary data and strings
	void CKtvSha1::Update(const unsigned char* data, unsigned int len)
	{
		unsigned long i = 0, j = 0;

		j = (m_count[0] >> 3) & 63;

		if((m_count[0] += len << 3) < (len << 3)) m_count[1]++;

		m_count[1] += (len >> 29);

		if((j + len) > 63)
		{
			ktvMemCpy(&m_buffer[j], data, (i = 64 - j));
			Transform(m_state, m_buffer);

			for (; i+63 < len; i += 64)
			{
				Transform(m_state, &data[i]);
			}

			j = 0;
		}
		else i = 0;

		ktvMemCpy(&m_buffer[j], &data[i], len - i);
	}

	void CKtvSha1::Final()
	{
		unsigned long i = 0, j = 0;
		unsigned char finalcount[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };

		for (i = 0; i < 8; i++)
			finalcount[i] = (unsigned char)((m_count[(i >= 4 ? 0 : 1)]
				>> ((3 - (i & 3)) * 8) ) & 255); // Endian independent

		Update((unsigned char *)"\200", 1);

		while ((m_count[0] & 504) != 448)
			Update((unsigned char *)"\0", 1);

		Update(finalcount, 8); // Cause a SHA1Transform()

		for (i = 0; i < 20; i++)
		{
			m_digest[i] = (unsigned char)((m_state[i >> 2] >> ((3 - (i & 3)) * 8) ) & 255);
		}

		// Wipe variables for security reasons
		i = 0; j = 0;
		ktvMemSet(m_buffer, 0, 64);
		ktvMemSet(m_state, 0, 20);
		ktvMemSet(m_count, 0, 8);
		ktvMemSet(finalcount, 0, 8);

		Transform(m_state, m_buffer);
	}

	// Get the final hash as a pre-formatted string
	void CKtvSha1::ReportHash(char *szReport, unsigned char uReportType)
	{
		unsigned char i = 0;
		char szTemp[4] = {0};

		if(uReportType == REPORT_HEX)
		{
			ktvSprintf(szTemp,  "%02x", m_digest[0]);
			ktvStrCat(szReport, szTemp);

			for(i = 1; i < 20; i++)
			{
				ktvSprintf(szTemp, "%02x", m_digest[i]);
				ktvStrCat(szReport, szTemp);
			}
		}
		else if(uReportType == REPORT_DIGIT)
		{
			ktvSprintf(szTemp, "%u", m_digest[0]);
			ktvStrCat(szReport, szTemp);

			for(i = 1; i < 20; i++)
			{
				ktvSprintf(szTemp, " %u", m_digest[i]);
				ktvStrCat(szReport, szTemp);
			}
		}
		else ktvStrCpy(szReport, "Error: Unknown report type!");
	}

	// Get the raw message digest
	void CKtvSha1::GetHash(unsigned char *uDest)
	{
		ktvMemCpy(uDest, m_digest, 20);
	}

